using System;
using System.Collections.Generic;
using System.Text;
using Imagination.Display;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Imagination.Physics;

namespace Imagination.Diagnostics
{
    class DebugScreen : Screen
    {
        private ImaginationEngine engine;
        private SpriteBatch batch;
        //private Font font;
        private ContentManager content;
        SpriteFont font;

        private string console;
        private string input;
        private string engineVersion;

        private KeyboardState oldKeyState;

        private List<Thing> thingsToTrack;

        public DebugScreen(ImaginationEngine engine, Game game)
            : base(game)
        {
            this.engine = engine;
            this.blocksUpdate = false;
            this.blocksDraw = false;
            this.console = string.Empty;
            this.thingsToTrack = new List<Thing>();
        }

        public override void Initialize()
        {
            content = new ContentManager(Game.Services);
            engineVersion = "Imagination v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
            base.Initialize();
        }

        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                batch = new SpriteBatch(this.GraphicsDevice);
#if XBOX360
                font = content.Load<SpriteFont>("Content\\Imagination\\Fonts\\debug");
#else
                font = content.Load<SpriteFont>("Content\\Imagination\\Fonts\\debug");
#endif
            }
        }

        public override void Draw(Microsoft.Xna.Framework.GameTime gameTime)
        {
            batch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            Color fontColor = new Color(new Vector4(1f, 1f, 1f, 0.7f));
            Color consoleColor = new Color(new Vector4(1f, 1f, 1f, 1f));
            Color inputColor = new Color(new Vector4(0f, 0f, 0f, 1f));

            batch.DrawString(font, engineVersion, new Vector2(10, 10), fontColor);
            batch.DrawString(font, gameTime.ElapsedGameTime.TotalSeconds.ToString(), new Vector2(10, 20), fontColor);

            //float posY = 10;
            //foreach (object service in Game.Services)
            //{
            //    font.Draw(service.ToString(), new Vector2(10, posY));
            //    posY += 10;
            //}

            batch.DrawString(font, String.Format("{0} Things", engine.ThingCount), new Vector2(10, 30), fontColor);
            batch.DrawString(font, engine.Partitioner.ToString(), new Vector2(10, 40), fontColor);
            batch.DrawString(font, engine.Physics.ToString(), new Vector2(10, 50), fontColor);
            batch.DrawString(font, engine.ScreenManager.ToString(), new Vector2(10, 60), fontColor);
            batch.DrawString(font, engine.CollisionDetector.ToString(), new Vector2(10, 70), fontColor);

            batch.DrawString(font, "> " + input, new Vector2(10, 80), inputColor);
            batch.DrawString(font, console, new Vector2(10, 100), consoleColor);

            string track = string.Empty;
            foreach (Thing thing in thingsToTrack)
            {
                track += string.Format("[{0}] {1}: p{2} v{3}\n",
                    thing.ID, thing.GetType().Name, thing.Position, thing.Velocity);
            }
            batch.DrawString(font, track, new Vector2(10, 300), consoleColor);

            batch.End();
        }

        private void ProcessConsoleInput()
        {
            input = input.Trim();
            string[] args = input.Split(' ');
            switch (args[0])
            {

                case "ADD":
                    if (args.Length >= 2)
                    {
                        //args[1] = "ImagineBalls.Ball";
                        Type type = thingsToTrack[0].GetType();
                        Thing newThing = Activator.CreateInstance(type) as Thing;
                        engine.AddThing(newThing);
                    }
                    break;

                case "LIST":
                    foreach(Thing thing in engine.EnumerateThings())
                    {
                        console = string.Format("[{0}] {1}: p{2} v{3}\n{4}",
                            thing.ID, thing.GetType().Name, thing.Position, thing.Velocity, console);
                    }
                    break;
                case "TRACK":
                    if (args.Length >= 2)
                    {
                        int thingID = int.Parse(args[1]);

                        // HACK: replace with Dictionary-based thing lookup by ID
                        Thing thing = engine.GetThing(thingID);
                        if (thing != null)
                            thingsToTrack.Add(thing);
                    }
                    break;
                case "KICK":
                    if (args.Length >= 2)
                    {
                        int thingID = int.Parse(args[1]);

                        // HACK: replace with Dictionary-based thing lookup by ID
                        Thing thing = engine.GetThing(thingID);
                        if (thing != null)
                        {
                            Force kickForce = new Force(new Vector3(0, 500, 0));
                            kickForce.IsTemporary = true;
                            thing.Forces.Add(kickForce);
                        }
                    }
                    break;

                case "NOTRACK":
                    if (args.Length >= 2)
                    {
                        int thingID = int.Parse(args[1]);

                        // HACK: replace with Dictionary-based thing lookup by ID
                        foreach (Thing thing in thingsToTrack)
                        {
                            if (thing.ID == thingID)
                            {
                                thingsToTrack.Remove(thing);
                                break;
                            }
                        }
                    }
                    break;
                case "CLEAR":
                case "CLS":
                    console = input = string.Empty;
                    break;
                default:
                    input = string.Format("command \"{0}\" is not understood", input);
                    break;
            }
            console = input + "\n" + console;
            input = string.Empty;
        }

        public override void Update(Microsoft.Xna.Framework.GameTime gameTime)
        {
            KeyboardState keyState = Keyboard.GetState();

            Keys[] keys = keyState.GetPressedKeys();
            Keys[] oldKeys = oldKeyState.GetPressedKeys();

            foreach (Keys pressed in keys)
            {
                bool found = false;
                for (int i = 0; i < oldKeys.Length; i++)
                    if (oldKeys[i].Equals(pressed))
                    {
                        found = true;
                        continue;
                    }
                if (!found)
                {
                    if (pressed.Equals(Keys.Enter))
                    {
                        ProcessConsoleInput();
                    }
                    else
                    {
                        if (pressed.Equals(Keys.Space))
                            input += " ";
                        else
                            if (pressed >= Keys.D0 && pressed <= Keys.D9)
                                input += (char)pressed;
                            else
                                input += pressed.ToString();
                    }
                }
            }

            oldKeyState = keyState;
        }
    }
}
